
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>布隆过滤器BloomFilter - 学习卡片</title>
      <style>
        body { font-family: sans-serif; background-color: #f0f8ff; color: #333; display: flex; flex-direction: column; align-items: center; padding: 50px 20px; }
        .header h1 { font-size: 32px; }
        .grid-container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; width: 100%; max-width: 1200px; }
        .card-container { perspective: 1200px; cursor: pointer; height: 250px; }
        .card { width: 100%; height: 100%; position: relative; transform-style: preserve-3d; transition: transform 0.7s; border-radius: 16px; box-shadow: 0 4px 16px rgba(0,0,0,0.08); }
        .card-container.flipped .card { transform: rotateY(180deg); }
        .card-face { position: absolute; width: 100%; height: 100%; backface-visibility: hidden; display: flex; flex-direction: column; box-sizing: border-box; border-radius: 16px; background-color: #fff; padding: 24px; }
        .card-back { background-color: #f0fff4; transform: rotateY(180deg); justify-content: space-between; }
        .card-category { font-size: 14px; color: #0052d9; margin-bottom: 8px; font-weight: 500; }
        .card-question { font-size: 20px; font-weight: 500; flex-grow: 1; display: flex; align-items: center; justify-content: center; text-align: center; }
        .card-answer-wrapper { flex-grow: 1; overflow-y: auto; }
        .card-answer { font-size: 15px; line-height: 1.7; }
        .card-footer { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 16px; margin-top: 16px; }
        .card-source { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 12px; margin-top: 12px; }
      </style>
    </head>
    <body>
      <div class="header">
        <h1>布隆过滤器BloomFilter - 学习卡片</h1>
      </div>
      <div class="grid-container">
        
    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">理论</div>
          <div class="card-question">布隆过滤器的核心思想是什么？它有哪些显著特点？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">理论</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">布隆过滤器的核心思想是使用一个位数组和多个哈希函数来判断元素是否存在。其显著特点包括：查询高效（O(k)时间复杂度）、空间节省、存在误判（可能将不存在的元素误判为存在），以及通常不支持删除元素。</div>
          </div>
          <div class="card-source">来源: 1.1 什么是布隆过滤器</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">Guava的BloomFilter是如何高效地生成多个哈希值的，而无需实现多个独立的哈希函数？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">Guava采用了一种“双重哈希”技术。它首先使用Murmur3算法计算一个128位的哈希值，然后将其分为两个64位的值（hash1和hash2）。通过公式 `hash1 + i * hash2` 来生成第i个哈希值。这种方法计算速度快，且生成的哈希值分布均匀，效率远高于计算k个独立哈希函数。</div>
          </div>
          <div class="card-source">来源: 1.3 哈希算法的选择</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">Guava BloomFilter底层的BitArray是如何实现的，以达到内存和性能上的优化？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">BitArray使用`long[]`数组来存储位数据，每个long可以存储64位，相比`boolean[]`更节省内存。它通过高效的位运算来设置和获取指定位的值，例如使用 `index >>> 6` (等效于除以64)来定位数组索引，使用位掩码 `(1L << index)` 来操作具体的位，从而获得极高的性能。</div>
          </div>
          <div class="card-source">来源: 1.4 底层位数组的实现</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">理论</div>
          <div class="card-question">哪三个核心因素决定了布隆过滤器的误判率？它们之间有什么关系？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">理论</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">决定布隆过滤器误判率的三个核心因素是：1. 位数组大小(m)；2. 哈希函数个数(k)；3. 插入元素的数量(n)。通常，位数组越大，误判率越低；插入的元素越多，误判率越高；哈希函数的个数则需要一个平衡值。</div>
          </div>
          <div class="card-source">来源: 2.1 误判率的理论分析</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">当在Guava中创建一个BloomFilter时，如何根据期望的元素数量和误判率来确定最优的位数组大小和哈希函数个数？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">Guava会根据用户提供的期望插入元素数量(n)和误判率(p)，通过两个数学公式自动计算最优参数：<br>1. 最优位数组大小 `m = -n * ln(p) / (ln(2))²`<br>2. 最优哈希函数个数 `k = (m/n) * ln(2)`<br>这确保了在满足误判率要求的前提下，使用最少的内存空间。</div>
          </div>
          <div class="card-source">来源: 2.2 最优参数的计算</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">模式</div>
          <div class="card-question">如何利用布隆过滤器来有效解决缓存穿透问题？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">模式</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">将所有可能存在的数据的键（例如商品ID）预先加载到布隆过滤器中。当一个查询请求到来时，首先通过布隆过滤器的`mightContain`方法检查这个键。如果返回`false`，则说明该键一定不存在，可以直接拒绝请求，从而避免了对缓存和数据库的无效查询。这能有效拦截大量对不存在数据的恶意攻击。</div>
          </div>
          <div class="card-source">来源: 4.2 使用BloomFilter解决缓存穿透</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">特性</div>
          <div class="card-question">标准布隆过滤器的一个主要局限性是什么？文档中提到了哪种替代方案来解决这个问题？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">特性</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">标准布隆过滤器的一个主要局限性是不支持删除元素。为了解决这个问题，可以使用“计数布隆过滤器”(Counting Bloom Filter)，它在位数组的每个位置上使用一个计数器而非单个比特位。添加元素时增加计数，删除时减少计数。当计数器归零时，才相当于元素被移除。</div>
          </div>
          <div class="card-source">来源: 5.1 不能删除元素的解决方案</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">策略</div>
          <div class="card-question">在动态数据场景下，如何维护布隆过滤器的数据一致性？文档介绍了哪两种更新策略？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">策略</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">文档介绍了两种更新策略：<br>1. **实时更新**：每当系统中添加新数据时，同步调用布隆过滤器的`put`方法将其加入。 <br>2. **定期重建**：设置一个定时任务，定期从数据源加载全量数据，构建一个新的布隆过滤器来替换旧的。实践中也可以将两种策略结合使用。</div>
          </div>
          <div class="card-source">来源: 4.3 增量更新的处理</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">应用</div>
          <div class="card-question">除了防护缓存穿透，布隆过滤器还适用于哪些典型的应用场景？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">应用</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">布隆过滤器还适用于多种场景，例如：<br>1. **垃圾邮件过滤**：快速判断邮件地址是否在黑名单中。<br>2. **URL去重**：网络爬虫判断一个URL是否已经被访问过。<br>3. **大集合的快速判断**：例如判断一个用户是否在某个庞大的黑名单集合中。</div>
          </div>
          <div class="card-source">来源: 5.2 布隆过滤器的实际应用场景</div>
        </div>
      </div>
    </div>

      </div>
    </body>
    </html>
